/*
 *    GeoTools Sample code and Tutorials by Open Source Geospatial Foundation, and others
 *    https://docs.geotools.org
 *
 *    To the extent possible under law, the author(s) have dedicated all copyright
 *    and related and neighboring rights to this software to the public domain worldwide.
 *    This software is distributed without any warranty.
 *
 *    You should have received a copy of the CC0 Public Domain Dedication along with this
 *    software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
 */
package org.geotools.render;

import java.awt.Dimension;
import java.awt.Rectangle;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.batik.svggen.SVGGeneratorContext;
import org.apache.batik.svggen.SVGGraphics2D;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.MapContent;
import org.geotools.renderer.lite.StreamingRenderer;
import org.w3c.dom.Document;

/**
 * This is a simple support class which allows you to generate an SVG file from a map.
 *
 * <p>To use, setup a Map object with the layers you want to render, create an envelope for the
 * region to be drawn and pass in an OutputStream (probably attached to a new file) for the
 * resulting SVG information to be stored in.
 *
 * <p>Optional you can change the default size of the SVG canvas (in effect increasing the
 * resolution).
 *
 * @author James Macgill, PennState
 * @version 2.8
 */
public class GenerateSVG {
    private static Logger LOGGER = org.geotools.util.logging.Logging.getLogger(GenerateSVG.class);

    // exportSVG start
    /**
     * Generate an SVG document from the supplied information. Note, use cavasSize first if you want
     * to change the default output size.
     *
     * @param map Contains the layers (features + styles) to be rendered
     * @param env The portion of the map to generate an SVG from
     * @param out Stream to write the resulting SVG out to (probable should be a new file)
     * @param canvasSize optional canvas size, will default to 300x300
     * @throws IOException Should anything go wrong whilst writing to 'out'
     * @throws ParserConfigurationException If critical XML tools are missing from the classpath
     */
    public static void exportSVG(
            MapContent map, ReferencedEnvelope env, OutputStream out, Dimension canvasSize)
            throws IOException, ParserConfigurationException {
        if (canvasSize == null) {
            canvasSize = new Dimension(300, 300); // default of 300x300
        }

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();

        // Create an instance of org.w3c.dom.Document
        Document document = db.getDOMImplementation().createDocument(null, "svg", null);

        // Set up the map
        SVGGeneratorContext ctx1 = SVGGeneratorContext.createDefault(document);
        SVGGeneratorContext ctx = ctx1;
        ctx.setComment("Generated by GeoTools2 with Batik SVG Generator");

        SVGGraphics2D g2d = new SVGGraphics2D(ctx, true);

        g2d.setSVGCanvasSize(canvasSize);

        StreamingRenderer renderer = new StreamingRenderer();
        renderer.setMapContent(map);

        Rectangle outputArea = new Rectangle(g2d.getSVGCanvasSize());
        ReferencedEnvelope dataArea = map.getMaxBounds();

        LOGGER.finest("rendering map");
        renderer.paint(g2d, outputArea, dataArea);
        LOGGER.finest("writing to file");
        try (OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
            g2d.stream(osw);
        }
    }
    // exportSVG end
}
